 

package com.zdkj.admin.service.impl;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zdkj.admin.api.dto.UserDTO;
import com.zdkj.admin.api.dto.UserInfo;
import com.zdkj.admin.api.entity.*;
import com.zdkj.admin.api.feign.RemoteSupportService;
import com.zdkj.admin.api.vo.MenuVO;
import com.zdkj.admin.api.vo.UserVO;
import com.zdkj.admin.mapper.SysUserMapper;
import com.zdkj.admin.service.*;
import com.zdkj.common.core.constant.CacheConstants;
import com.zdkj.common.core.constant.CommonConstants;
import com.zdkj.common.core.constant.SecurityConstants;
import com.zdkj.common.core.util.R;
import com.zdkj.common.data.datascope.DataScope;
import com.zdkj.common.data.tenant.TenantContextHolder;
import com.zdkj.common.security.util.ObjectUtils;
import com.zdkj.common.security.util.SecurityUtils;
import com.zdkj.admin.util.JdbcUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author cui_com
 * @date 2017/10/31
 */
@Slf4j
@Service
@AllArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
	private final SysMenuService sysMenuService;
	private final SysRoleService sysRoleService;
	private final SysDeptService sysDeptService;
	private final SysUserRoleService sysUserRoleService;
	private final SysDeptRelationService sysDeptRelationService;
	private final RemoteSupportService remoteSupportService;
	private final SysUserInfoChangeService sysUserInfoChangeService;

	/**
	 * 前端默认密码不更新
	 */
	private final String DEFAULT_PASSWORD = "thanks,zdkj";

	/**
	 * 保存用户信息
	 *
	 * @param userDto DTO 对象
	 * @return success/fail
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean saveUser(UserDTO userDto) {
		SysUser sysUser = new SysUser();
		BeanUtils.copyProperties(userDto, sysUser);
		sysUser.setDelFlag(CommonConstants.STATUS_NORMAL);
		sysUser.setPassword(ENCODER.encode(userDto.getPassword()));
		Integer tenantId = TenantContextHolder.getTenantId();
		baseMapper.insert(sysUser);
		String isRecordChange = userDto.getIsRecordChange();
		//非导入方式记录到设备操作号历史使用记录表
		if((isRecordChange==null || "".equals(isRecordChange) || "1".equals(isRecordChange)) && userDto.getBelongToLine()==false){
			SwPmDeviceOperationCodeRecord swPmDeviceOperationCodeRecord = new SwPmDeviceOperationCodeRecord();
			SwPmDeviceOperationCodeRecord defaultObj = ObjectUtils.getDefaultObj(SwPmDeviceOperationCodeRecord.class);
			BeanUtils.copyProperties(defaultObj, swPmDeviceOperationCodeRecord);
			swPmDeviceOperationCodeRecord.setLineCode(sysUser.getLineCode());
			swPmDeviceOperationCodeRecord.setStationCode(sysUser.getStationCode());
			swPmDeviceOperationCodeRecord.setOperationCode(sysUser.getDeviceOperateNo());
			swPmDeviceOperationCodeRecord.setUsePersonName(sysUser.getNikename());
			swPmDeviceOperationCodeRecord.setUsePersonCode(sysUser.getUserCode());
			remoteSupportService.swPmDeviceOperationCodeRecordSave(swPmDeviceOperationCodeRecord,SecurityConstants.FROM_IN);
			//非导入方式保存设备操作号基础数据
			//设备操作号添加到参数表 线路 车站 设备操作号都不为空的情况下
			if(userDto.getLineCode()!=null && !"".equals(userDto.getLineCode()) && userDto.getStationCode()!=null && !"".equals(userDto.getStationCode())&& userDto.getDeviceOperateNo()!=null && !"".equals(userDto.getDeviceOperateNo())){
			   remoteSupportService.insertDeviceOperation(userDto.getLineCode(),userDto.getStationCode(),userDto.getDeviceOperateNo());
		     }
		}
		List<SysUserRole> userRoleList = userDto.getRole()
				.stream().map(roleId -> {
					SysUserRole userRole = new SysUserRole();
					userRole.setUserId(sysUser.getUserId());
					userRole.setRoleId(roleId);
					return userRole;
				}).collect(Collectors.toList());
		
		/*用户在岗信息不必再维护
		if(!userDto.getBelongToLine()) {
			SwPmStationPersonGuard swPmStationPersonGuard = new SwPmStationPersonGuard();
			swPmStationPersonGuard.setLineCode(userDto.getLineCode());
			swPmStationPersonGuard.setStationCode(userDto.getStationCode());
			swPmStationPersonGuard.setUserCode(userDto.getUserCode());
			//未在岗
			swPmStationPersonGuard.setGuardStatus("0");
			remoteSupportService.stationPersonGuardSave(swPmStationPersonGuard, SecurityConstants.FROM_IN);
		}*/
		return sysUserRoleService.saveBatch(userRoleList);
	}

	/**
	 * 锁定账号
	 * @param username
	 * @return
	 */
	@Override
	public Boolean lockUser(String username) {
		SysUser user = baseMapper.selectOne(new QueryWrapper<SysUser>().eq("username",username));
		user.setLockFlag(CommonConstants.STATUS_LOCK);
		return baseMapper.updateById(user) == 1;
	}

	/**
	 * 通过查用户的全部信息
	 *
	 * @param sysUser 用户
	 * @return
	 */
	@Override
	public UserInfo findUserInfo(SysUser sysUser) {
		UserInfo userInfo = new UserInfo();
		userInfo.setSysUser(sysUser);
		//设置角色列表  （ID）
		List<Integer> roleIds = sysRoleService.findRolesByUserId(sysUser.getUserId())
				.stream()
				.map(SysRole::getRoleId)
				.collect(Collectors.toList());
		userInfo.setRoles(ArrayUtil.toArray(roleIds, Integer.class));

		//设置权限列表（menu.permission）
		Set<String> permissions = new HashSet<>();
		roleIds.forEach(roleId -> {
			List<String> permissionList = sysMenuService.findMenuByRoleId(roleId)
					.stream()
					.filter(menuVo -> StringUtils.isNotEmpty(menuVo.getPermission()))
					.map(MenuVO::getPermission)
					.collect(Collectors.toList());
			permissions.addAll(permissionList);
		});
		userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));
		return userInfo;
	}



	/**
	 * 分页查询用户信息（含有角色信息）
	 *
	 * @param page    分页对象
	 * @param userDTO 参数列表
	 * @return
	 */
	@Override
	public IPage getUsersWithRolePage(Page page, UserDTO userDTO) {
		return baseMapper.getUserVosPage(page, userDTO, new DataScope());
	}

	/**
	 * 分页查询用户信息（查特定角色（手工清出设备人员）的用户信息）
	 *
	 * @param page    分页对象
	 * @param userDTO 参数列表
	 * @return
	 */
	@Override
	public IPage getUsersWithRoleCodePage(Page page,String roleCode, UserDTO userDTO){
		return baseMapper.getUsersWithRoleCodePage(page, userDTO, roleCode,new DataScope());
	}

	/**
	 * 通过ID查询用户信息
	 *
	 * @param id 用户ID
	 * @return 用户信息
	 */
	@Override
	public UserVO selectUserVoById(Integer id) {
		return baseMapper.getUserVoById(id);
	}

	/**
	 * 删除用户
	 *
	 * @param sysUser 用户
	 * @return Boolean
	 */
	@Override
	@CacheEvict(value = {CacheConstants.USER_DETAILS,CacheConstants.LOGIN_FAIL_COUNT}, key = "#sysUser.username")
	public Boolean deleteUserById(SysUser sysUser) {
		sysUserRoleService.deleteByUserId(sysUser.getUserId());
		try{
			String sql ="delete from sys_user where user_id="+sysUser.getUserId();
			JdbcUtil.exeSqlCrud(sql);

		}catch(Exception e){
			
		}
		//this.removeById(sysUser.getUserId());
		return Boolean.TRUE;
	}

	@Override
	@CacheEvict(value = {CacheConstants.USER_DETAILS,CacheConstants.LOGIN_FAIL_COUNT}, key = "#userDto.username")
	public R<Boolean> updateUserInfo(UserDTO userDto) {
		SysUser userVO = baseMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername,userDto.getUsername()));
		SysUser sysUser = new SysUser();
		if (StrUtil.isNotBlank(userDto.getPassword())
				&& StrUtil.isNotBlank(userDto.getNewpassword1())) {
			if (ENCODER.matches(userDto.getPassword(), userVO.getPassword())) {
				sysUser.setPassword(ENCODER.encode(userDto.getNewpassword1()));
			} else {
				log.warn("原密码错误，修改密码失败:{}", userDto.getUsername());
				return R.ok(Boolean.FALSE, "原密码错误，修改失败");
			}
		}
		sysUser.setPhone(userDto.getPhone());
		sysUser.setUserId(userVO.getUserId());
		sysUser.setAvatar(userDto.getAvatar());
		return R.ok(this.updateById(sysUser));
	}

	@Override
	@CacheEvict(value = {CacheConstants.USER_DETAILS,CacheConstants.LOGIN_FAIL_COUNT}, key = "#userDto.username")
	@Transactional(rollbackFor = Exception.class)
	public Boolean updateUser(UserDTO userDto) {
		SysUser oldUser = this.getById(userDto.getUserId());
		SysUser sysUser = new SysUser();
		BeanUtils.copyProperties(userDto, sysUser);
		//防止lineCode和stationCode为null
		optionNull(sysUser);
		optionNull(oldUser);

		String isRecordChange = userDto.getIsRecordChange();
        //非导入方式记录到设备操作号历史使用记录表
		if((isRecordChange==null || "".equals(isRecordChange) || "1".equals(isRecordChange)) && userDto.getBelongToLine()==false){
			//记录人员信息变更
		    if(isNeedToRecordChange(userDto.getRole(),oldUser,sysUser)){
        	    //recordUserChange(userDto.getRole(),oldUser,sysUser);
	        }
		    if(StringUtils.isNotEmpty(oldUser.getDeviceOperateNo()) && !oldUser.getDeviceOperateNo().equals(sysUser.getDeviceOperateNo())){
				SwPmDeviceOperationCodeRecord swPmDeviceOperationCodeRecord = new SwPmDeviceOperationCodeRecord();
				SwPmDeviceOperationCodeRecord defaultObj = ObjectUtils.getDefaultObj(SwPmDeviceOperationCodeRecord.class);
				BeanUtils.copyProperties(defaultObj, swPmDeviceOperationCodeRecord);
				swPmDeviceOperationCodeRecord.setLineCode(sysUser.getLineCode());
				swPmDeviceOperationCodeRecord.setStationCode(sysUser.getStationCode());
				swPmDeviceOperationCodeRecord.setOperationCode(sysUser.getDeviceOperateNo());
				swPmDeviceOperationCodeRecord.setUsePersonName(sysUser.getNikename());
				swPmDeviceOperationCodeRecord.setUsePersonCode(sysUser.getUserCode());
				remoteSupportService.swPmDeviceOperationCodeRecordSave(swPmDeviceOperationCodeRecord,SecurityConstants.FROM_IN);
			}
			//非导入方式保存设备操作号基础数据
			//设备操作号添加到参数表 线路 车站 设备操作号都不为空的情况下
			if(userDto.getLineCode()!=null && !"".equals(userDto.getLineCode()) && userDto.getStationCode()!=null && !"".equals(userDto.getStationCode())&& userDto.getDeviceOperateNo()!=null && !"".equals(userDto.getDeviceOperateNo())){
			   remoteSupportService.insertDeviceOperation(userDto.getLineCode(),userDto.getStationCode(),userDto.getDeviceOperateNo());
		     }
		}

		//记录人员信息变更
//		if(isNeedToRecordChange(userDto.getRole(),oldUser,sysUser)){
//			recordUserChange(userDto.getRole(),oldUser,sysUser);
//		}

		sysUser.setUpdateTime(LocalDateTime.now());

		if (StrUtil.isNotBlank(userDto.getPassword())) {
			sysUser.setPassword(ENCODER.encode(userDto.getPassword()));
		}
		//如果是页面呈现的默认密码，则不更改原始密码
		if(DEFAULT_PASSWORD.equals(userDto.getPassword())){
			sysUser.setPassword(null);
		}


		this.updateById(sysUser);

		sysUserRoleService.remove(Wrappers.<SysUserRole>update().lambda()
				.eq(SysUserRole::getUserId, userDto.getUserId()));
		List<Integer> userRoles = userDto.getRole();
		if(ObjectUtil.isNotEmpty(userRoles)){
			userRoles.forEach(roleId -> {
				SysUserRole userRole = new SysUserRole();
				userRole.setUserId(sysUser.getUserId());
				userRole.setRoleId(roleId);
				userRole.insert();
			});
		}



		return Boolean.TRUE;
	}

	/**
	 * 更新指定用户状态及密码等信息
	 *
	 * @param userDto 用户信息
	 * @return
	 */
	@Override
	@CacheEvict(value = {CacheConstants.USER_DETAILS,CacheConstants.LOGIN_FAIL_COUNT}, key = "#sysUser.username")
	@Transactional(rollbackFor = Exception.class)
	public Boolean updateUserStatusPassword(SysUser sysUser){
	     return this.updateById(sysUser);
	
	}

	//校验null
	private void optionNull(SysUser user) {

		if(StringUtils.isEmpty(user.getLineCode())){
			user.setLineCode("");
		}
		if(StringUtils.isEmpty(user.getStationCode())){
			user.setStationCode("");
		}
		if(StringUtils.isEmpty(user.getDeviceOperateNo())){
			user.setDeviceOperateNo("");
		}
	}

	/**
	 * 记录人员信息变更
	 * @param role
	 * @param oldUser
	 * @param sysUser
	 */
	@Transactional(rollbackFor = Exception.class)
	public void recordUserChange(List<Integer> role, SysUser oldUser, SysUser sysUser) {

		SysUserInfoChange sysUserInfoChange = new SysUserInfoChange();

		//原线路&车站
		if(!oldUser.getBelongToLine()){

			String oldLineName = remoteSupportService.getLineNameByCode(oldUser.getLineCode()).getData();
			sysUserInfoChange.setLineOld(oldLineName);

			if(StringUtils.isNotEmpty(oldUser.getStationCode())){
				//Object oldStation = remoteSupportService.getStationByCode(oldUser.getStationCode()).getData();
				
				String name = remoteSupportService.getLnameAndSnameByCode(oldUser.getLineCode(),oldUser.getStationCode()).getData();
			    if(StringUtils.isNotEmpty(name)){
				    String[] split = name.split(",");
				    //user.setLineName(split[0]);
				    //user.setStationName(split[1]);
					sysUserInfoChange.setStationOld(split[1]);
			     }
				/*
				if(null != oldStation){
					JSONObject oldStationJSONObject = JSONObject.parseObject(JSON.toJSONString(oldStation));
					if(null != oldStationJSONObject && null != oldStationJSONObject.get("name")){
						String oldStationName = oldStationJSONObject.get("name").toString();
						sysUserInfoChange.setStationOld(oldStationName);
					}
				}*/
			}


		}
		//新线路&车站
		if(!sysUser.getBelongToLine()){
			String newLineName = remoteSupportService.getLineNameByCode(sysUser.getLineCode()).getData();
			sysUserInfoChange.setLineNew(newLineName);

			if(StringUtils.isNotEmpty(sysUser.getStationCode())){
				//Object newStation = remoteSupportService.getStationByCode(sysUser.getStationCode()).getData();
				String name = remoteSupportService.getLnameAndSnameByCode(sysUser.getLineCode(),sysUser.getStationCode()).getData();
               if(StringUtils.isNotEmpty(name)){
				    String[] split = name.split(",");
				    //user.setLineName(split[0]);
				    //user.setStationName(split[1]);
					sysUserInfoChange.setStationNew(split[1]);
			     }
				 /*
				if(null != newStation){
					JSONObject newStationJSONObject = JSONObject.parseObject(JSON.toJSONString(newStation));
					if(null != newStationJSONObject && null != newStationJSONObject.get("name")){
						String newStationName = newStationJSONObject.get("name").toString();
						sysUserInfoChange.setStationNew(newStationName);
					}

				}*/
			}

		}

		//部门
		if(ObjectUtil.isNotEmpty(oldUser.getDeptId())){
			SysDept oldDept = sysDeptService.getById(oldUser.getDeptId());
			sysUserInfoChange.setDeptOld(oldDept.getName());
		}
		if(ObjectUtil.isNotEmpty(sysUser.getDeptId())){
			SysDept newDept = sysDeptService.getById(sysUser.getDeptId());
			sysUserInfoChange.setDeptNew(newDept.getName());
		}


		//岗位
		SysUserRole oldUserRole = sysUserRoleService.getOne(Wrappers.<SysUserRole>query().lambda()
				.eq(SysUserRole::getUserId,oldUser.getUserId()));
		if(ObjectUtil.isNotEmpty(oldUserRole)){
			SysRole oldRole = sysRoleService.getById(oldUserRole.getRoleId());
			sysUserInfoChange.setRoleOld(oldRole.getRoleName());
		}

		if(ObjectUtil.isNotEmpty(role)){
			//角色暂时只支持1对1
			SysRole newRole = sysRoleService.getById(role.get(0));
			sysUserInfoChange.setRoleNew(newRole.getRoleName());
		}

		sysUserInfoChange.setUserId(sysUser.getUserId());
		sysUserInfoChange.setUserCode(sysUser.getUserCode());
		sysUserInfoChange.setUserName(sysUser.getNikename());

		sysUserInfoChangeService.save(sysUserInfoChange);

	}

	/**
	 * 判断是否需要记录人员信息变更
	 * 部门|线路|车站|岗位发生变更
	 *
	 * @param roleList
	 * @param oldUser
	 * @param sysUser
	 * @return
	 */
	private boolean isNeedToRecordChange(List<Integer> roleList, SysUser oldUser, SysUser sysUser) {
		if(!oldUser.getDeptId().equals(sysUser.getDeptId())
				|| !oldUser.getStationCode().equals(sysUser.getStationCode())
		        || !oldUser.getLineCode().equals(sysUser.getLineCode())){
			return true;
		}

		SysUserRole role = sysUserRoleService.getOne(Wrappers.<SysUserRole>query().lambda()
				.eq(SysUserRole::getUserId,sysUser.getUserId()));

		if(role==null){
			return false;
		}

		Integer roleId = role.getRoleId();

		//目前只支持关联一个角色
		//判断角色是否发生变更
		if(!roleList.isEmpty() && roleId != null && !roleId.equals(roleList.get(0))){
			return true;
		}

		return false;
	}

	/**
	 * 查询上级部门的用户信息
	 *
	 * @param username 用户名
	 * @return R
	 */
	@Override
	public List<SysUser> listAncestorUsers(String username) {
		SysUser sysUser = this.getOne(Wrappers.<SysUser>query().lambda()
				.eq(SysUser::getUsername, username));

		SysDept sysDept = sysDeptService.getById(sysUser.getDeptId());
		if (sysDept == null) {
			return null;
		}

		Integer parentId = sysDept.getParentId();
		return this.list(Wrappers.<SysUser>query().lambda()
				.eq(SysUser::getDeptId, parentId));
	}

	/**
	 * 获取当前用户的子部门信息
	 *
	 * @return 子部门列表
	 */
	private List<Integer> getChildDepts() {
		Integer deptId = SecurityUtils.getUser().getDeptId();
		//获取当前部门的子部门
		return sysDeptRelationService
				.list(Wrappers.<SysDeptRelation>query().lambda()
						.eq(SysDeptRelation::getAncestor, deptId))
				.stream()
				.map(SysDeptRelation::getDescendant)
				.collect(Collectors.toList());
	}

	/**
	 * 获取线路所属的部门信息
	 * @param code
	 * @return
	 */
	@Override
	public Map<String,String> getLineDeptInfoByCode(String code){
         return baseMapper.getLineDeptInfoByCode(code);
	}

	/**
	 * 下载机电模板
	 * @param response
	 */
	@Override
	public void exportTamplatesJD(HttpServletResponse response) {
		String  verifyConfirmName = "机电人员信息模板";
		String  tableName = "sys_user_person_jd";

		BufferedInputStream br = null;
		OutputStream out = null;
		try {
			response.reset(); // 非常重要
			response.setContentType("application/vnd.ms-excel");
			response.setCharacterEncoding("utf-8");
			final String fileName = URLEncoder.encode(verifyConfirmName, "UTF-8");
			response.setHeader("Content-disposition", "attachment;filename=" + fileName + System.currentTimeMillis() + ".xls");

			br =  new BufferedInputStream(this.getClass().getResourceAsStream("/static/excel/template/import/" + tableName + ".xls"));

			byte[] buf = new byte[1024];
			int len = 0;

			out = response.getOutputStream();
			while ((len = br.read(buf)) > 0) {
				out.write(buf, 0, len);
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(out != null) {
				try {
					out.close();
				} catch (IOException ioe) {
					ioe.printStackTrace();
				}
			}
			if(br != null){
				try {
					br.close();
				} catch (IOException ioe) {
					ioe.printStackTrace();
				}
			}
		}
	}


	/**
	 * 下载客运模板
	 * @param response
	 */
	@Override
	public void exportTamplatesKY(HttpServletResponse response) {
		String  verifyConfirmName = "客运人员信息模板";
		String  tableName = "sys_user_person_ky";

		BufferedInputStream br = null;
		OutputStream out = null;
		try {
			response.reset(); // 非常重要
			response.setContentType("application/vnd.ms-excel");
			response.setCharacterEncoding("utf-8");
			final String fileName = URLEncoder.encode(verifyConfirmName, "UTF-8");
			response.setHeader("Content-disposition", "attachment;filename=" + fileName + System.currentTimeMillis() + ".xls");

			br =  new BufferedInputStream(this.getClass().getResourceAsStream("/static/excel/template/import/" + tableName + ".xls"));

			byte[] buf = new byte[1024];
			int len = 0;

			out = response.getOutputStream();
			while ((len = br.read(buf)) > 0) {
				out.write(buf, 0, len);
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(out != null) {
				try {
					out.close();
				} catch (IOException ioe) {
					ioe.printStackTrace();
				}
			}
			if(br != null){
				try {
					br.close();
				} catch (IOException ioe) {
					ioe.printStackTrace();
				}
			}
		}
	}
}
